Jetpack Compose 中的 Modifier
在传统开发中,使用XML文件来描述组件的样式,而Jetpack Compose设计了一个精妙的东西,它叫作Modifier。
Jetpack Compose 是 Android 中用于构建用户界面的现代化工具包。其中,Modifier 是一个非常重要的概念,它允许我们对 UI 组件进行各种样式和布局的调整。在本篇博客中,我们将深入了解 Modifier,以及如何在 Compose 中使用它。
1.1 Modifier常用
Modifier 是一种修饰符,它允许我们在 Compose 中对 UI 进行各种样式和布局的调整。相对于传统布局有 Margin 和 Padding 之分,Compose 中只有 padding 这一种修饰符,根据在调用链中的位置不同发挥不同作用。这体现了 Modifier 中链式调用的特点,使概念更加简洁。
对比理解
我们先拿XML中的FrameLayout做下对比,如下,我们在xml文件中定义了一个 宽度填充满父容器,高度200dp,背景为黑色,内容边距为16dp的 FrameLayout:
<FrameLayout
android:layout_width="match_parent"
android:layout_height="200dp"
android:background="#000000"
android:padding="16dp" >
<-- 可配置子级元素 -->
</FrameLayout>那么在Compose中如何实现这样的UI呢?直接来看结果,了解下Modifier是如何配合Composable函数实现的:
@Composable
fun BoxDemo() {
Box(
modifier = Modifier
.fillMaxWidth()
.height(200.dp)
.background(Color.Black)
.padding(16.dp),
) {
//可配置子级元素
}
}这样你理解了吗Modifier的作用?
1.1 添加背景色
- background:backgroud修饰符用来为被修饰组件添加背景色。背景色支持设置color的纯色背景,也可以使用brush设置渐变色背景。Brush是Compose提供的用来创建线性渐变色的工具。
Box(
modifier = Modifier
.size(100.dp)
.background(Color.Red)
) {
// UI 组件
}
1.2 填充最大宽度,高度
有的时候想要让组件在高度或者宽度上填满父空间,此时可以使用fillMaxXXX系列方法:
fillMaxWidth:填充最大宽度
fillMaxHeight:填充最大宽度
Column(
modifier = Modifier
.fillMaxWidth()
.fillMaxHeight()
.drawBehind {
drawRect(DarkBlue)
}
) {}
1.3 设置大小
- size: 先来介绍最常用的size修饰符,它用来设置被修饰组件的大小。
Box(
modifier = Modifier
.size(100.dp)
) {
// UI 组件
}
1.4 设置布局参数
- 通过
fillMaxWidth()
和height()
方法,我们可以设置 UI 组件的宽度和高度。
Box(
modifier = Modifier
.fillMaxWidth()
.height(100.dp)
.background(Color.Red)
) {
// UI 组件
}
1.5 内边距
- 使用
padding
方法可以为 UI 组件添加内边距。padding用来为被修饰组件增加间隙。可以在border前后各插入一个padding,区分对外和对内的间距
Box(
modifier = Modifier
.size(100.dp)
.background(Color.Red)
.padding(16.dp)
) {
// UI 组件
}
1.6 外边距
- 使用
offset
方法可以将 UI 组件移动到指定的位置。:offset修饰符用来移动被修饰组件的位置,我们在使用时只分别传入水平方向与垂直方向的偏移量即可。
Box(
modifier = Modifier
.size(100.dp)
.offset(x = 200.dp, y = 150.dp)
.background(Color.Red)
) {
// UI 组件
}
1.7 渐变
- 通过
background
方法和Brush.verticalGradient
可以设置 UI 组件的渐变背景色
Box(
modifier = Modifier
.size(100.dp)
.background(
brush = Brush.verticalGradient(
colors = listOf(Color.Red, Color.Yellow),
startY = 0f,
endY = 100f
)
)
) {
// UI 组件
}
1.2 详细API
1.2.1 宽度
- Modifier.width(width: Dp):
- 功能: 直接设定组件的宽度为指定的dp值。
- 应用场景: 当你需要一个固定宽度的组件,比如按钮、图标等,不随父容器变化时。
- Modifier.widthIn(min: Dp = Dp.Unspecified, max: Dp = Dp.Unspecified):
- 功能: 设定组件的宽度范围,允许子元素在该范围内自适应,超出部分仍可见。
- 应用场景: 在设计可伸缩但又需限制最大或最小尺寸的组件时非常有用,如列表项的宽度调整。
- Modifier.fillMaxWidth(fraction: Float = 1f):
- 功能: 使组件的宽度填充其父容器的宽度,可通过
fraction
参数控制填充比例。 - 应用场景: 实现全宽按钮、分割线等需要横跨屏幕的元素,或者按比例分配空间给多个并排组件。
- 功能: 使组件的宽度填充其父容器的宽度,可通过
- Modifier.wrapContentWidth(align: Alignment.Horizontal = Alignment.CenterHorizontally, unbounded: Boolean = false):
- 功能: 根据子组件的实际内容决定宽度,
align
控制内容对齐方式,unbounded
决定是否忽略最大宽度限制。 - 应用场景: 适用于文本、图片等需要根据内容自适应大小的场景,特别是当希望内容居中或对齐时。
- 功能: 根据子组件的实际内容决定宽度,
- Modifier.preferredWidth(width: Dp):
- 功能: 设置组件的首选宽度,但如果布局约束允许,宽度仍可能改变。
- 应用场景: 为组件提供一个理想宽度,同时保持布局的灵活性,如自定义卡片宽度。
- Modifier.preferredWidth(intrinsicSize: IntrinsicSize):
- 功能: 实验性功能,旨在使组件宽度与其子元素的固有最小或最大宽度相匹配。
IntrinsicSize.Min
或IntrinsicSize.Max
指定计算方式。 - 应用场景: 对于那些希望自动适应其内容最小或最大尺寸需求的复杂自定义组件特别有用,但需要注意这是实验性API,可能随Compose库更新而变化。
- 功能: 实验性功能,旨在使组件宽度与其子元素的固有最小或最大宽度相匹配。
- Modifier.preferredWidthIn(min: Dp = Dp.Unspecified, max: Dp = Dp.Unspecified):
- 功能: 设置组件的首选宽度范围,提供了更灵活的宽度控制,允许组件在指定的最小和最大宽度之间自适应。
- 应用场景: 当需要组件在不同屏幕尺寸下保持相对一致的宽度范围,同时又能够根据可用空间适度调整时。
1.2.2 高度
Modifier.height(height: Dp):
- 功能: 直接设定组件的高度为指定的dp值。
- 应用场景: 对于需要固定高度的元素,如按钮、标题栏等。
Modifier.heightIn(min: Dp = Dp.Unspecified, max: Dp = Dp.Unspecified):
- 功能: 限制组件的高度范围,允许在最小和最大高度内自适应,超出部分仍然可见。
- 应用场景: 控制列表项、卡片等的高度范围,确保内容的可读性同时适应不同屏幕尺寸。
Modifier.fillMaxHeight(fraction: Float = 1f):
- 功能: 使组件高度填充其父容器高度,可以通过
fraction
参数控制填充比例。 - 应用场景: 实现全高的背景、分隔栏等,或者按比例分配垂直空间给多个上下排列的组件。
- 功能: 使组件高度填充其父容器高度,可以通过
Modifier.wrapContentHeight(align: Alignment.Vertical = Alignment.CenterVertically, unbounded: Boolean = false):
- 功能: 根据子组件内容的高度自动调整组件高度,
align
控制垂直对齐方式,unbounded
决定是否忽略最大高度限制。 - 应用场景: 文本段落、图片视图等,当内容高度不确定时,保持内容自然流式布局。
- 功能: 根据子组件内容的高度自动调整组件高度,
Modifier.preferredHeight(intrinsicSize: IntrinsicSize):
- 功能: 实验性功能,使组件高度与其子元素的固有高度相匹配,通过
IntrinsicSize.Min
或IntrinsicSize.Max
指定。 - 应用场景: 对于那些需要基于内容自然尺寸调整高度的自定义组件,虽然此功能处于实验阶段,但能提升布局的自适应能力。
- 功能: 实验性功能,使组件高度与其子元素的固有高度相匹配,通过
Modifier.preferredHeight(height: Dp):
- 功能: 设置组件的首选高度,实际高度可能会根据布局约束调整。
- 应用场景: 设定一个理想的组件高度,同时保持布局的灵活性,适用于多种视图组件。
Modifier.preferredHeightIn(min: Dp = Dp.Unspecified, max: Dp = Dp.Unspecified):
- 功能: 指定组件高度的首选最小和最大值范围,组件高度会在该范围内自适应。
- 应用场景: 在需要高度具有一定弹性范围,同时又希望保持一定上下限的场景中使用,提高布局的适应性和美观性。
1.2.3 大小
- Modifier.size(size: Dp):
- 功能: 同时设定组件的宽度和高度为相同的dp值,创建一个正方形或等比例缩放的矩形区域。
- 应用场景: 对于需要保持宽高比固定的图像展示、按钮或其他图形元素。
- Modifier.size(width: Dp, height: Dp):
- 功能: 分别指定组件的宽度和高度,实现自定义的尺寸控制。
- 应用场景: 当组件需要具有特定宽度和高度时,比如固定大小的卡片、图标等。
- Modifier.sizeIn(minWidth: Dp = Dp.Unspecified, minHeight: Dp = Dp.Unspecified, maxWidth: Dp = Dp.Unspecified, maxHeight: Dp = Dp.Unspecified):
- 功能: 为组件设置尺寸范围,允许在指定的最小和最大尺寸内自适应。
- 应用场景: 在不同屏幕尺寸和方向上保持组件尺寸的适配性和一致性,如响应式布局设计。
- Modifier.fillMaxSize(fraction: Float = 1f):
- 功能: 让组件的尺寸填充其父容器,通过
fraction
参数可以控制填充比例。 - 应用场景: 实现全屏背景、对话框等覆盖整个父容器的视图,或者按比例分配空间。
- 功能: 让组件的尺寸填充其父容器,通过
- Modifier.wrapContentSize(align: Alignment = Alignment.Center, unbounded: Boolean = false):
- 功能: 根据内容的尺寸自动调整组件的尺寸,
align
控制内容的对齐方式,unbounded
决定是否忽略最大尺寸限制。 - 应用场景: 自适应内容的布局,如文本框、滚动视图等,确保内容能自然显示而不受外部硬性尺寸限制。
- 功能: 根据内容的尺寸自动调整组件的尺寸,
- Modifier.preferredSize(size: Dp) 和 Modifier.preferredSize(width: Dp, height: Dp):
- 功能: 分别或同时设置组件的首选宽度和高度,实际尺寸可能根据布局约束调整。
- 应用场景: 当希望组件有一个期望尺寸但也能根据布局条件适当调整时。
- Modifier.preferredSizeIn(minWidth: Dp = Dp.Unspecified, minHeight: Dp = Dp.Unspecified, maxWidth: Dp = Dp.Unspecified, maxHeight: Dp = Dp.Unspecified):
- 功能: 设置组件的首选尺寸范围,包括最小和最大宽度与高度。
- 应用场景: 在需要保持组件尺寸有一定弹性范围,同时又想控制其极限值的场景中使用。
1.2.4 内边距
- Modifier.padding(start: Dp = 0.dp, top: Dp = 0.dp, end: Dp = 0.dp, bottom: Dp = 0.dp):
- 功能: 分别设置组件在开始(通常对应于左)、顶部、结束(通常对应于右)、底部四个方向上的内边距。
- 应用场景: 当需要对组件的每一边进行独立控制,以达到精细的布局调整时使用,例如调整按钮四周的空白空间。
- Modifier.padding(horizontal: Dp = 0.dp, vertical: Dp = 0.dp):
- 功能: 便捷设置,分别指定水平(左右)和垂直(上下)方向的统一内边距。
- 应用场景: 当组件在水平或垂直方向上有相同间距需求时,可以简化代码,提高效率。
- Modifier.padding(all: Dp):
- 功能: 统一设置组件四周的所有内边距为同一值。
- 应用场景: 对于需要快速设置等距离填充,简化布局代码的场景,如为一系列具有相同间距的列表项设置样式。
- Modifier.padding(padding: PaddingValues):
- 功能: 使用
PaddingValues
对象来设置内边距,PaddingValues
是一个更灵活的参数,可以包含上述任何一种设置方式,支持对齐和偏移等高级特性。 - 应用场景: 高度定制化的布局需求,比如响应不同的屏幕方向、窗口Insets(如系统栏)等情况,提供最大的灵活性。
- 功能: 使用
- Modifier.absolutePadding(left: Dp = 0.dp, top: Dp = 0.dp, right: Dp = 0.dp, bottom: Dp = 0.dp):
- 功能: 直接设置组件的绝对内边距,不考虑文本方向或布局方向的影响,即“左”始终指屏幕左侧,“右”始终指屏幕右侧。
- 应用场景: 在不需要考虑国际化和文本方向变化的场景下,简化内边距设置过程,适合于一些固定布局或特定需求的界面元素。
1.2.5 外边距
Compose没有直接提供名为margin
的Modifier方法来设置外边距,因为它的设计理念鼓励通过组合和嵌套组件来实现布局,而不是依赖于绝对定位或外边距概念。
- Modifier.offset(x: Dp = 0.dp, y: Dp = 0.dp) 水平和竖直方向上的偏移,单位dp,值可以为正也可以为负,无需考虑国际化的问题。
- Modifier.offset(offset: Density.() -> IntOffset) 偏移,单位px,可以结合动画进行元素的偏移处理;
- Modifier.offsetPx(x: State
<Float>
= mutableStateOf(0f), y: State<Float>
= mutableStateOf(0f)) - 带有状态的偏移量【已废弃】,请使用上一个函数;
- Modifier.absoluteOffset(x: Dp = 0.dp, y: Dp = 0.dp)
- Modifier.absoluteOffset(offset: Density.() -> IntOffset)
- Modifier.absoluteOffsetPx(x: State<
Float
> = mutableStateOf(0f), y: State<Float
> = mutableStateOf(0f))
1.3 作用域限定Modifier修饰符
Compose充分发挥了Kotlin的语法特性,让某些Modifier修饰符只能在特定作用域中使用,有利于类型安全地调用它们。所谓的作用域
,在Kotlin中就是一个带有Receiver的代码块。例如Box组件参数中的conent就是一个Reciever类型为BoxScope的代码块,因此其子组件都处于BoxScope作用域中
1.3.1 matchParentSize
- matchParentSize是只能在BoxScope中使用的作用域限定修饰符。当使用matchParentSize设置尺寸时,可以保证当前组件的尺寸与父组件相同。而父组件默认的是wrapContent,会根据UserInfo的尺寸确定自身的尺寸。
1.3.2 weight
- 在RowScope与ColumnScope中,可以使用专属的weight修饰符来设置尺寸。与size修饰符不同的是,weight修饰符允许组件通过百分比设置尺寸,也就是允许组件可以自适应适配各种屏幕尺寸的移动终端设备。